﻿using GN.Pay.TradeChannel.Configure;
using GN.Pay.TradeChannel.DefaultImpl;
using GN.Pay.TradeChannel.Exceptions;
using GN.Pay.Utils.Security;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;

namespace GN.Pay.TradeChannel.Gyb
{
    /// <summary>
    /// 安全帮助
    /// </summary>
    public static class SecurityUtils
    {
        private static HashAlgorithm Hash_Algorithm = new MD5CryptoServiceProvider();//MD5withRSA

        /// <summary>
        /// Byte转16进制
        /// </summary>
        /// <param name="inbuf"></param>
        /// <returns></returns>
        private static string ByteToHex(byte[] inbuf)
        {
            StringBuilder strBuf = new StringBuilder();
            for (int i = 0; i < inbuf.Length; i++)
            {
                string byteStr = (inbuf[i] & 0xFF).ToString("x");
                if (byteStr.Length != 2)
                {
                    strBuf.Append('0').Append(byteStr);
                }
                else
                {
                    strBuf.Append(byteStr);
                }
            }
            return strBuf.ToString();
        }

        /// <summary>
        /// 16进制转byte
        /// </summary>
        /// <param name="hexString"></param>
        /// <returns></returns>
        private static byte[] HexToByte(string hexString)
        {
            if (string.IsNullOrEmpty(hexString))
            {
                hexString = "00";
            }
            byte[] returnBytes = new byte[hexString.Length / 2];
            for (int i = 0; i < returnBytes.Length; i++)
            {
                returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
            }
            return returnBytes;
        }

        /// <summary>
        /// 获取签名证书提供程序
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        public static RSACryptoServiceProvider GetSignProvider(ChannelPfxSignConfigureInfo info)
        {
            var raw = info.SignPfxRaw();
            if (raw == null)
            {
                throw new TradeChannelException(TradeChannelErrorCode.Configure, "Gyb", "未配置签名Pfx");
            }
            if (string.IsNullOrWhiteSpace(info.SignPfxPassWord))
            {
                throw new TradeChannelException(TradeChannelErrorCode.Configure, "Gyb", "未配置签名Pfx的密码");
            }
            return RsaUtils.PrivateKeyProvider(raw, info.SignPfxPassWord);
        }
        
        /// <summary>
        /// 获取签名验证证书提供程序
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        public static RSACryptoServiceProvider GetSignVerifyProvider(ChannelPfxSignConfigureInfo info)
        {
            if (string.IsNullOrWhiteSpace(info.SignVerifyCerRawBase64))
            {
                throw new TradeChannelException(TradeChannelErrorCode.Configure, "Gyb", "未配置签名验证公钥 PaySignVerifyCerRawBase64 ");
            }
            return RsaUtils.PublicKeyProvider(info.SignVerifyCerRaw());
        }

        /// <summary>
        /// 签名
        /// </summary>
        /// <param name="configureInfo">配置</param>
        /// <param name="dataStr">待签名字符串</param>
        /// <returns></returns>
        public static string Sign(ChannelPfxSignConfigureInfo configureInfo, string dataStr)
        {            
            using (var provider = GetSignProvider(configureInfo))
            {
                byte[] data = Encoding.UTF8.GetBytes(dataStr);
                byte[] res = provider.SignData(data, Hash_Algorithm);
                return ByteToHex(res);
            }
        }

        /// <summary>
        /// 验签
        /// </summary>
        /// <param name="configureInfo"></param>
        /// <param name="sign"></param>
        /// <param name="sourceContext"></param>
        /// <returns></returns>
        public static bool SignVerify(ChannelPfxSignConfigureInfo configureInfo, string sign, string sourceContext)
        {
            using (var rsaProvider = GetSignVerifyProvider(configureInfo))
            {
                byte[] srcData = Encoding.UTF8.GetBytes(sourceContext);
                byte[] signData = HexToByte(sign);
                return rsaProvider.VerifyData(srcData, Hash_Algorithm, signData);
            }
        }
    }
}
